#ifndef CHARCLASS_H
#define CHARCLASS_H

#include "pattern.h"
#include "node.h"
#include <cctype>
#include <string>
using std::string;

class CharClass : public Node
{
public:
    CharClass(Pattern* p)
        :Node(p){}

    virtual bool contain(char c) = 0;
    virtual bool match(Matcher *m, size_t from, const string &text){
        if(from >= text.length())
            return false;
        if(contain(text[from])){
            m->setLastMatchTo(from);
            return next->match(m,from+1,text);
        }
        return false;
    }
    CharClass* getComplement();
    CharClass* getUnion(CharClass* other);
    CharClass* getIntersecion(CharClass* other);

    static CharClass* space(Pattern* p);
    static CharClass* digit(Pattern* p);
    static CharClass* word(Pattern* p);
};

class SingleCharClass : public CharClass{
public:
    SingleCharClass(Pattern* p,char _ch)
        :CharClass(p)
    {
        ch = _ch;
    }

    virtual bool contain(char c){
        return c == ch;
    }

private:
    char ch;
};

class IgnoreCaseSingleCharClass : public CharClass{
public:
    IgnoreCaseSingleCharClass(Pattern* p,char _ch)
        :CharClass(p)
    {
        ch = _ch;
    }

    virtual bool contain(char c){
        return tolower(c) == ch || toupper(c) == ch;
    }

private:
    char ch;
};

class RangeCharClass : public CharClass{
public:
    RangeCharClass(Pattern* p,char lowBound,char highBound)
        :CharClass(p)
    {
        l = lowBound;
        h = highBound;
    }

    virtual bool contain(char c){
        return l<=c && c<=h;
    }

private:
    char l,h;
};

class IgnoreCaseRangeCharClass : public CharClass{
public:
    IgnoreCaseRangeCharClass(Pattern* p,char f,char t)
        :CharClass(p)
    {
        from = f;
        to = t;
    }

    virtual bool contain(char c){
        char cl = tolower(c);
        char cu = toupper(c);
        return (from<=cl && cl<=to) || (from<=cu && cu<=to);
    }

private:
    char from,to;
};

class DiscreteCharClass : public CharClass{
public:
    DiscreteCharClass(Pattern* p,const char* seq)
        :CharClass(p),s(seq)
    {

    }
    DiscreteCharClass(Pattern *p, char c)
        :CharClass(p)
    {
        s.push_back(c);
    }

    void add(char c){
        s.push_back(c);
    }

    virtual bool contain(char c){
        return s.find(c) != -1;
    }

private:
    std::string s;
};

// decorators
class ReverseCharClass : public CharClass{
public:
    ReverseCharClass(Pattern* p,CharClass* _a)
        :CharClass(p)
    {
        a = _a;
    }
    virtual bool contain(char c){
        return !(a->contain(c));
    }

private:
    CharClass* a;
};

class UnionCharClass : public CharClass{
public:
    UnionCharClass(Pattern* p,CharClass* _a,CharClass* _b)
        :CharClass(p)
    {
        a = _a;
        b = _b;
    }

    virtual bool contain(char c){
        return a->contain(c) || b->contain(c);
    }
private:
    CharClass* a;
    CharClass* b;
};

class IntersectCharClass : public CharClass{
public:
    IntersectCharClass(Pattern* p,CharClass* _a,CharClass* _b)
        :CharClass(p)
    {
        a = _a;
        b = _b;
    }

    virtual bool contain(char c){
        return a->contain(c) && b->contain(c);
    }
private:
    CharClass* a;
    CharClass* b;
};

#endif // CHARCLASS_H
